home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Pascal / OffscreenToys / OffscreenToys 1.3 / OffscreenToysUtils.p < prev   
Text File  |  1995-01-11  |  11KB  |  347 lines

  1. {Minimalist's offscreen package - reuseable code from OffscreenToys.}
  2.  
  3. {This unit implements glue for using "cicn" resources and GWorlds. It works on all Macs I can}
  4. {imagine, including Macs without 32-bit QD or Color QD.}
  5.  
  6. unit OffscreenToysUtils;
  7.  
  8. interface
  9.     uses
  10. {$IFC UNDEFINED THINK_PASCAL}
  11.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps, Desk, Memory,{}
  12.         SegLoad, Scrap, ToolUtils, OSEvents, OSUtils, Menus, Resources, Packages, {}
  13. {$ENDC}
  14.         QDOffScreen;
  15.  
  16. {Generate a random number in a limited range}
  17. {function Rand (range: integer): integer;}
  18.  
  19. {Glue for GWorlds}
  20.     procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
  21.     procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
  22.  
  23. {Glue for cicns}
  24.     function OTGetCicn (cicnId: integer): CIconHandle;
  25.     procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
  26.     procedure OTDisposeCicn (theCicn: CIconHandle);
  27.     function OTGetBoostCicn (cicnId: integer): GrafPtr;
  28.     procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
  29.  
  30. {NewPtr with built-in error check}
  31.     function OTNewPtr (size: Longint): Ptr;
  32.  
  33. {Glue for making GWorlds}
  34.     procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
  35.     procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
  36.  
  37. {Apples code for TrapAvailable}
  38.     function TrapAvailable (theTrap: Integer): Boolean;
  39.  
  40. {Initialize the globals - must be done first!}
  41.     procedure OTInitGlobals;
  42.  
  43.     var
  44.         gColorQDFlag: Boolean;        {True if 32-bit QD exists. If not, we run everything in b/w.}
  45.         gHasWNE: Boolean;        {True if we can use WaitNextEvent}
  46.         gSoundFlag: Boolean;        {True if Sound Manager is around.}
  47.  
  48. implementation
  49.  
  50. {Taken out from:}
  51. { --- PART 2: Various general, reuseable routines, mostly glue: ---------------------}
  52.  
  53. {Rand: simply make a random number between 0 and range-1.}
  54.  
  55.     function Rand (range: integer): integer;
  56.     begin
  57.         Rand := abs(Random mod range)
  58.     end;
  59.  
  60. {BailOut: Emergency exit. We go here on most errors. Real programs report what the}
  61. {problem is. You may wish to put a breakpoint in BailOut when debugging.}
  62.  
  63.     procedure BailOut;
  64.     begin
  65.         SysBeep(1); {Minimal error message. Use alert in real programs.}
  66.         halt;
  67.     end;
  68.  
  69. {OTGetGWorld and OTSetGWorld: Glue to GetGWorld and SetGWorld, so this will work}
  70. {without 32-bit QD, if necessary.}
  71.  
  72.     procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
  73.     begin
  74.         theDevice := nil;
  75.         if gColorQDFlag then
  76.             GetGWorld(CGrafPtr(thePort), theDevice)
  77.         else
  78.             GetPort(thePort);
  79.     end;
  80.  
  81.     procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
  82.     begin
  83.         if gColorQDFlag then
  84.             SetGWorld(CGrafPtr(thePort), theDevice)
  85.         else
  86.             SetPort(thePort);
  87.     end;
  88.  
  89. {OTGetCicn: Glue to GetCIcon, loads a cicn resource}
  90.  
  91.     function OTGetCicn (cicnId: integer): CIconHandle;
  92.         var
  93.             h: Handle;
  94.     begin
  95.         if gColorQDFlag then
  96.             begin
  97.                 OTGetCicn := GetCIcon(cicnId);
  98.                 h := GetResource('cicn', cicnID);
  99.                 ReleaseResource(h);
  100.             end
  101.         else
  102.             OTGetCicn := CIconHandle(GetResource('cicn', cicnId));
  103.     end;
  104.  
  105. {OTPlotCicn: Glue to PlotCIcon, plots a cicn.}
  106.  
  107.     procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
  108.         var
  109.             tempIconBMap, tempIconMask: BitMap;
  110.             savePort: GrafPtr;
  111.             saveDevice: GDHandle;
  112.             datasize: integer;
  113.     begin
  114.         OTGetGWorld(savePort, saveDevice);
  115.         if destWorld <> nil then
  116.             OTSetGWorld(destWorld, nil)
  117.         else
  118.             destWorld := savePort; {So that CopyMask has a GrafPtr!}
  119.         if theCicn <> nil then {If we have a cicn}
  120.             if gColorQDFlag then {We have color - then it's easy.}
  121.                 PlotCicon(r, theCicn)
  122.             else
  123. {No color: Use CopyMask.}
  124. {NOTE: This only works for 9 pixels or wider cicn's! (Old QuickDraw can't handle 1 byte wide bitmaps.)}
  125. {There is a workaround for this, but that is *really* tedious.}
  126.                 begin
  127.                     HLock(Handle(theCicn));
  128. {Make the base address pointers valid}
  129.                     with theCicn^^.iconBMap do
  130.                         datasize := rowBytes * (bounds.bottom - bounds.top);
  131.                     theCicn^^.iconBMap.baseAddr := Ptr(longint(@theCicn^^.iconMaskData[0]) + datasize); {Bitmappen måste vara giltig fört!}
  132.                     theCicn^^.iconMask.baseAddr := @theCicn^^.iconMaskData[0]; {Maskbitmappen måste också vara giltig först!}
  133. {Draw with CopyMask}
  134.                     CopyMask(theCicn^^.iconBMap, theCicn^^.iconMask, destWorld^.portBits, theCicn^^.iconBMap.bounds, theCicn^^.iconBMap.bounds, r);
  135.                     HUnLock(Handle(theCicn));
  136.                 end;
  137.         OTSetGWorld(savePort, saveDevice);
  138.     end;
  139.  
  140.     procedure OTDisposeCicn (theCicn: CIconHandle);
  141.     begin
  142.         if gColorQDFlag then
  143.             DisposeCIcon(theCicn)
  144.         else
  145.             ReleaseResource(Handle(theCicn));
  146.     end;
  147.  
  148. {To avoid a lot of boring checks later, we have a glue for NewPtr, making it emergency}
  149. {exit on out of memory. (This is of course often not what you want, but this is a demo!)}
  150.  
  151.     function OTNewPtr (size: Longint): Ptr;
  152.     begin
  153.         OTNewPtr := NewPtrClear(size);
  154.         if MemError <> noErr then
  155.             BailOut;
  156.     end;
  157.  
  158. {OTNewGWorld: Glue to NewGWorld}
  159. {I declare offscreenGWorld as GrafPtr to save us a bunch of typecasts later (in CopyBits).}
  160. {Most parameters to NewGWorld omitted - NewGWorld is smart enough to make the defaults useable.}
  161.  
  162.     procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
  163.         var
  164.             theDevice, oldDevice: GDHandle;
  165.             ourCMHandle: CTabHandle;
  166.             err: OsErr;
  167.  
  168.             saveGD: GDHandle;
  169.             savePort: GrafPtr;
  170.     begin
  171.         OTGetGWorld(savePort, saveGD);
  172.  
  173.         if gColorQDFlag then
  174.             begin
  175.                 if noErr <> NewGWorld(GWorldPtr(offscreenGWorld), 0, boundsRect, nil, nil, [pixelsLocked]) then
  176.                     BailOut;
  177. {We lock the offscreen pixmap so we can CopyBits and PlotCIcon to it.}
  178.                 if LockPixels(CGrafPtr(offscreenGWorld)^.portPixMap) then
  179.                     ;
  180. {Note: We should unlock it (UnlockPixels) when not animating, to avoid memory fragmentation,}
  181. {but you can bother with that later if it's a problem.}
  182.             end
  183.         else
  184.             begin
  185. {Not color - setup in b/w}
  186.                 offscreenGWorld := GrafPtr(OTnewPtr(sizeof(GrafPort)));
  187.                 OpenPort(offscreenGWorld);
  188.                 offscreenGWorld^.portRect := boundsRect;
  189.                 offscreenGWorld^.portBits.bounds := offscreenGWorld^.portRect;
  190.  
  191.                 RectRgn(offscreenGWorld^.visRgn, boundsRect);
  192.                 ClipRect(boundsRect);
  193.  
  194.                 offscreenGWorld^.portBits.rowBytes := longint(((offscreenGWorld^.portRect.right - offscreenGWorld^.portRect.left + 15) div 16) * 2);
  195.                 offscreenGWorld^.portBits.baseAddr := OTnewPtr(offscreenGWorld^.portBits.rowBytes * longint(offscreenGWorld^.portRect.bottom - offscreenGWorld^.portRect.top));
  196.             end;
  197.  
  198.         OTSetGWorld(savePort, saveGD);
  199.     end;
  200.  
  201. {OTDisposeGWorld: Glue to DisposeGWorld}
  202.  
  203.     procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
  204.     begin
  205.         if gColorQDFlag then
  206.             begin
  207.                 DisposeGWorld(GWorldPtr(offscreenGWorld));
  208.             end
  209.         else
  210.             begin
  211.                 DisposePtr(offscreenGWorld^.portBits.baseAddr);
  212.                 DisposePtr(Ptr(offscreenGWorld));
  213.             end;
  214.         offscreenGWorld := nil;
  215.     end;
  216.  
  217.  
  218. {TrapAvailable from IM6-3-8}
  219.     function NumToolboxTraps: Integer;
  220.     begin
  221.         if NGetTrapAddress($A86E, ToolTrap) = NGetTrapAddress($aa6e, ToolTrap) then {_InitGraf}
  222.             NumToolboxTraps := $200
  223.         else
  224.             NumToolboxTraps := $400;
  225.     end;
  226.     function GetTrapType (theTrap: Integer): TrapType;
  227.         const
  228.             TrapMask = $800;
  229.     begin
  230.         if band(theTrap, TrapMask) > 0 then
  231.             GetTrapType := ToolTrap
  232.         else
  233.             GetTrapType := OSTrap;
  234.     end;
  235.     function TrapAvailable (theTrap: Integer): Boolean;
  236.         var
  237.             tType: TrapType;
  238.     begin
  239.         tType := GetTrapType(theTrap);
  240.         if tType = ToolTrap then
  241.             begin
  242.                 theTrap := band(theTrap, $7ff);
  243.                 if theTrap >= NumToolboxTraps then
  244.                     theTrap := $A89F;{_Unimplemented}
  245.             end;
  246.         TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress($A89F, ToolTrap);{_Unimplemented}
  247.     end;
  248. {End of code from IM6}
  249.  
  250.     procedure OTInitGlobals;
  251.         const
  252. {Trap numbers}
  253.             _WaitNextEvent = $A860;
  254.             _GetCIcon = $AA1E; {E.g. any Color QuickDraw routine}
  255.             k32bQD = $AB1D;
  256.             _SndPlay = $A805;
  257.     begin
  258.         gHasWNE := TrapAvailable(_WaitNextEvent);
  259.         gColorQDFlag := TrapAvailable(k32bQD) and TrapAvailable(_GetCIcon); {???}
  260.         gSoundFlag := TrapAvailable(_SndPlay);
  261. {$IFC UNDEFINED THINK_PASCAL}
  262.         qd.randSeed := TickCount;            {Seed the random number generator - TickCount is good enough.}
  263. {$ELSEC}
  264.         randSeed := TickCount;                {Seed the random number generator - TickCount is good enough.}
  265. {$ENDC}
  266.     end;
  267.  
  268.  
  269.  
  270.  
  271. {Load a cicn to a GWorld. Wastes some memory, but if it isn't too many, the speed increase pays}
  272. {for it.}
  273.  
  274.     function OTGetBoostCicn (cicnId: integer): GrafPtr;
  275.         var
  276.             offscreenGWorld: GrafPtr;
  277.             theCicn: CIconHandle;
  278.             saveGD: GDHandle;
  279.             savePort: GrafPtr;
  280.     begin
  281.         OTGetGWorld(savePort, saveGD);
  282.         theCicn := OTGetCicn(cicnId);
  283.         OTNewGWorld(offscreenGWorld, theCicn^^.iconMask.bounds);
  284.         if offscreenGWorld <> nil then
  285.             begin {OTSetGWorld(offscreenGWorld, nil); Onödigt!}
  286.                 OTPlotCicn(theCicn, offscreenGWorld, theCicn^^.iconMask.bounds);
  287.  
  288. {I use the clipRgn for storing the mask region. This may seem weird, but when we aren't drawing}
  289. {in the GWorld anyway, it won't matter.}
  290.                 if offscreenGWorld = nil then
  291.                     offscreenGWorld^.clipRgn := NewRgn;
  292.                 if gColorQDFlag and TrapAvailable($A8D7) then {a8d7 = BitMapToRegion}
  293.                     begin
  294.                         if noErr <> BitMapToRegion(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
  295.                             offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
  296.                     end
  297.                 else {Trap not available - use the glue routine instead.}
  298.                     begin
  299.                         if noErr <> BitMapToRegionGlue(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
  300.                             offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
  301.                     end;
  302.  
  303.                 OTDisposeCicn(theCicn);
  304.             end;
  305.         OTSetGWorld(savePort, saveGD);
  306.         OTGetBoostCicn := offscreenGWorld;
  307.     end;
  308.  
  309.     var
  310.         gTmpRgn: RgnHandle;
  311.  
  312.     procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
  313.         var
  314.             saveGD: GDHandle;
  315.             savePort: GrafPtr;
  316.             bounds: Rect;
  317.             tmpRgn: RgnHandle;
  318.             saveForeColor, saveBackColor: RGBColor;
  319.     begin
  320.         OTGetGWorld(savePort, saveGD);
  321. {OTSetGWorld(theCicn, nil);}
  322.         bounds := theCicn^.portRect;
  323.         OffsetRect(bounds, where.h - bounds.left, where.v - bounds.top);
  324.  
  325.         if gTmpRgn = nil then
  326.             gTmpRgn := NewRgn; {For top speed, we make this global, and create it only once!}
  327.         CopyRgn(theCicn^.clipRgn, gTmpRgn);
  328.         OffsetRgn(gTmpRgn, where.h, where.v);
  329.         SetPort(destPort); {Device?}
  330.         if gColorQDFlag then
  331.             begin
  332.                 GetForeColor(saveForeColor);
  333.                 GetBackColor(saveBackColor);
  334.             end;
  335.         ForeColor(blackColor);
  336.         BackColor(whiteColor);
  337.         CopyBits(theCicn^.portBits, destPort^.portBits, theCicn^.portRect, bounds, srcCopy, gTmpRgn);
  338. {DisposeRgn(tmpRgn);}
  339.         if gColorQDFlag then
  340.             begin
  341.                 RGBForeColor(saveForeColor);
  342.                 RGBBackColor(saveBackColor);
  343.             end;
  344.         OTSetGWorld(savePort, saveGD);
  345.     end;
  346.  
  347. end.